#!coding:utf-8
# vim: tabstop=4 shiftwidth=4 softtabstop=4
"""
nat
===========================
<network>
  <name>net2</name>
  <forward mode='nat'/>
  <bridge stp='on' delay='0' />
  <mac address='52:54:00:06:AF:D3'/>
  <ip address='10.0.0.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='10.0.0.2' end='10.0.0.254' />
    </dhcp>
  </ip>
</network>

===============================

isolate
====================================
<network>
  <name>ii</name>
  <bridge stp='on' delay='0' />
  <mac address='52:54:00:4A:70:82'/>
  <ip address='192.168.100.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.100.128' end='192.168.100.254' />
    </dhcp>
  </ip>
</network>

==================================

existing host bridge

==================================
<network>
  <name>host-bridge</name>
  <forward mode="bridge"/>
  <bridge name="br0"/>
</network>
=================================


指定设备 :
<forward mode='nat' dev='eth0'/>
不指定设备则用于所有设备

forward:
nat
route
bridge
private
vepa
passthrough
hostdev

"""
from lxml import etree
from cvirt.cnode.libvirtXmlObject.baseDomain import XmlObject
from cvirt.common import exception


class Network(XmlObject):
    ROOT_NAME = 'network'
    RNG_NAME = 'network'
    def __init__(self, parse_xml=None, name=None, uuid=None, stp='off', delay=0,
                 mac=None, bridge=None,**kw):
        "以下是network公共的属性"

        self.name = name
        self.uuid = uuid
        self.stp = stp
        self.delay = delay

        self.mac = mac
        self.bridge = bridge

        super(Network, self).__init__(parse_xml=parse_xml, **kw)

    def _parse_xml(self, xmldoc):
        for c in xmldoc.getchildren():
            if c.tag == 'name':
                self.name = c.text
            elif c.tag == 'uuid':
                self.uuid = c.text
            elif c.tag == 'bridge':
                if 'stp' in c.keys():
                    self.stp = c.get('stp')
                if 'delay' in c.keys():
                    self.delay = c.get('delay')
                if 'name' in c.keys():
                    self.bridge = c.get('name')
            elif c.tag == 'mac':
                self.mac = c.get('address')
        self._network_parse(xmldoc)  #sub class implements this for parse rest xml

    # def _validate(self):
    #     if not self.name:
    #         raise exception.Error('name can not be null')
    #     self._network_validate()  #sub class implements this for validate

    def _get_xml_config(self, root):
        network = root

        if self.name:
            network.append(self._set_text("name", self.name))
        if self.uuid:
            network.append(self._set_text('uuid', self.uuid))

        network.append(etree.Element('bridge',stp=self.stp,delay=str(self.delay)))

        if self.mac:
            network.append(etree.Element('mac', address=self.mac))

        return network

class NATNetwork(Network):
    "nat 网络需要ip，和dhcp子元素"
    MODE = 'nat'
    FORWOARD = True
    def __init__(self, parse_xml=None, dev=None, name=None, uuid=None, stp='on', delay=0,
                 mac=None, netmask=None,
                 dhcp_start=None, dhcp_end=None, address=None, bridge=None,**kw):
        self.dev = dev
        self.address = address
        self.netmask = netmask

        self.dhcp_start = dhcp_start
        self.dhcp_end = dhcp_end
        self.mode = None

        super(NATNetwork, self).__init__(parse_xml, name, uuid, stp, delay,
                                         mac, bridge,**kw)

    # def _network_validate(self):
    #     if self.mode != self.MODE:
    #         raise exception.Error('forward element must be exists, and mode = <%s>' % self.MODE)
    #     if self.address is None:
    #         raise exception.Error('ip element must have <address> attr')
    #     if self.netmask is None:
    #         raise exception.Error('ip element must have <netmask> attr')

    def _network_parse(self, xmldoc):
        for c in xmldoc.getchildren():
            if c.tag == 'forward' and self.FORWOARD:
                self.mode = c.get('mode')
                self.dev = c.get('dev')
            elif c.tag == 'ip':
                self.address = c.get('address')
                self.netmask = c.get('netmask')
                for c in c.getchildren():
                    if c.tag == 'start':
                        self.dhcp_start = c.get('start')
                    elif c.tag == 'end':
                        self.dhcp_end = c.get('end')

    def _get_xml_config(self, root):
        network = super(NATNetwork,self)._get_xml_config(root)
        if self.FORWOARD:
            forward = etree.Element("forward", mode=self.MODE)
            if self.dev: forward.set('dev',self.dev)
            network.append(forward)
        if self.address and self.netmask:
            ip_element = etree.Element('ip', address=self.address, netmask=self.netmask)
            if self.dhcp_start and self.dhcp_end:
                dhcp = etree.Element('dhcp')
                dhcp.append(etree.Element('range', start=self.dhcp_start, end=self.dhcp_end))
                ip_element.append(dhcp)
            network.append(ip_element)
        return network



class IsolateNetwork(NATNetwork):
    "隔离网络和nat网络唯一的不同就是隔离网络没有forward元素"
    FORWOARD = False  #isolate do not need forward element


class BridgeNetwork(Network):
    MODE = 'bridge'
    def __init__(self, parse_xml=None, name=None, uuid=None, stp='off', delay=0,
                 mac=None,bridge=None, **kw):
        self.bridge = bridge
        self.mode = None
        super(BridgeNetwork, self).__init__(parse_xml, name, uuid, stp, delay,
                                         mac, bridge,**kw)
    # def _network_validate(self):
    #     if self.mode != self.MODE:
    #         raise exception.Error('forward element must be exists, and mode = <%s>' % self.MODE)
    #     if not self.bridge:
    #         raise exception.Error('bridge network must specify a bridge')

    def _network_parse(self,xmldoc):
        forward = xmldoc.find('./forward')
        if forward is not None:
            self.mode = forward.get('mode')

    def _get_xml_config(self, root):
        network = root
        if self.name:
            network.append(self._set_text("name", self.name))
        if self.uuid:
            network.append(self._set_text('uuid', self.uuid))
        network.append(etree.Element('forward',mode=self.MODE))
        network.append(etree.Element('bridge',name=self.bridge))

        return network







